from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional, List









# class User(BaseModel):
#     id: int
#     name: str
#     age: int
#     # signup_ts: datetime
#     signup_ts: Optional[datetime]  = None



# user_data = {
#     'id': '123',
#     'name': 'John Doe',
#     'age': 30,
#     'signup_ts': '2023-01-01 12:34'
# }

# """
#         1.  类型可以转换  如   id 是 int  传入的 是  字符串 '123'  pydantic 会自动转换为 int
#         2.  如果明显不能转的 会报错，如 age 是int 如果传入 “fsf” 此时会报错
#         3.  如果参数数目对不上也会报错，除非参数设定为可选的，如 signup_ts: Optional[datetime] = None
# """

# try:
#     print(User(id=123, name='John Doe', age="30"))
#     # user = User(**user_data)
#     # print(user)

# except ValidationError as e:
#     print(e.json())














# class Item(BaseModel):
#     name: str
#     description: str = None
#     price: float
#     tax: float = None

# class Order(BaseModel):
#     id: int
#     items: List[Item]  # 嵌套模型




# class Item(BaseModel):
#     name: str
#     description: str = None
#     price: float = Field(gt=0)   # 价格必须大于0的浮点数
#     tax: float = None



# from pydantic import validator

# class Item(BaseModel):
#     name: str
#     price: float

#     @validator('name')
#     def name_must_be_capitalized(cls, v):
#         if not v[0].isupper():
#             raise ValueError('Name must start with a capital letter')
#         return v









"""
1. **模型继承（Model Inheritance）**:

你可以通过继承来复用模型字段和验证逻辑。

2. **自定义验证器（Custom Validators）**:

使用 `@validator` 装饰器来创建自定义验证逻辑。

3. **根验证器（Root Validators）**:

对整个模型数据进行验证，可以使用 `@root_validator`。

4. **ORM 模式（从 ORM 对象创建模型实例）**:

使用 `from_orm` 方法将 ORM 对象（如 SQLAlchemy 模型）转换为 Pydantic 模型。

5. **字段别名（Field Aliases）**:

在字段定义中使用 `Field` 和 `alias` 参数来处理不同的字段名（例如，API 使用 snake_case，而模型使用 camelCase）。

6. **动态模型创建（Dynamic Model Creation）**:

使用 `create_model` 函数在运行时动态创建模型。

7. **使用 Config 类定制模型行为**:

通过定义嵌套的 `Config` 类来配置模型的行为，例如设置环境变量前缀、设置别名生成规则等。

8. **递归模型（Recursive Models）**:

定义包含自身类型的模型（例如树形结构）。

9. **数据类型转换（Data Parsing and Conversion）**:

Pydantic 在验证时会自动转换数据类型（例如，将字符串转换为整数）。

10. **使用 `@root_validator(pre=True)` 进行预处理**:

在验证之前对原始输入数据进行处理。

11. **模型方法（Model Methods）**:

在模型上定义方法，以便于业务逻辑处理。

12. **模型属性（Computed Fields）**:

使用 `@property` 装饰器定义计算字段，但注意这些字段不会被验证。在 Pydantic v2 中，可以使用 `computed_field`。

13. **模型导出（Exporting Models）**:

使用 `model_dump()` 或 `model_dump_json()` 方法将模型导出为字典或 JSON。

14. **严格模式（Strict Mode）**:

在字段上设置 `strict=True` 来禁用类型转换，要求输入类型必须匹配。

15. **使用 `Literal` 类型**:

从 `typing` 导入 `Literal` 来定义字段只能接受特定的字面量值。

16. **联合类型（Union Types）**:

使用 `Union` 或 `|`（Python 3.10+）来允许字段为多种类型之一。

17. **约束类型（Constrained Types）**:

使用 `constr`, `conint`, `confloat` 等来定义带约束的字段（例如字符串长度、数值范围）。

18. **环境变量支持（Settings Management）**:

结合 `BaseSettings`（在 Pydantic v1 中）或 `pydantic_settings`（v2）来管理应用配置。

19. **验证器之间的依赖关系（Validator Dependencies）**:

在验证器中可以指定依赖的字段，当依赖字段变化时重新验证。

20. **自定义数据类型（Custom Data Types）**:

通过继承 `pydantic.types.ConstrainedType` 或使用 `Annotated` 创建自定义数据类型。
"""



# # 动态模型创建
# from pydantic import create_model, Field

# DynamicModel = create_model(
#     "DynamicModel",
#     name=(str, Field(..., max_length=100)),
#     value=(int, Field(default=42, ge=0)),
#     is_active=(bool, True)  # 默认值
# )

# obj = DynamicModel(name="test", value=10)
# print(obj.model_dump())  # 输出: {'name': 'test', 'value': 10, 'is_active': True}


# ----------- TODO:
# from typing import List
# from pydantic import BaseModel, ValidationError

# class IntList(BaseModel):
#     root_model: List[int]  # 直接验证整数列表

# data = IntList(root_model=[1, 2, 3])
# print(data.model_dump())  # 输出: {'root_model': [1, 2, 3]}


"""
try:
    from pydantic import RootModel
except ImportError:
    # 回退到 V1 的 __root__ 方式
    from pydantic import BaseModel
    class RootModel(BaseModel):
        __root__: list
"""


# from pydantic import RootModel, Field
# from typing import List
# ---------------------------------------------------------------------
# # 定义根模型 (直接验证列表)
# class IntList(RootModel):
#     root: list[int]  # 直接验证整数列表

# # 使用方式
# data = IntList([1, 2, 3])
# print(data.model_dump())  # 输出: [1, 2, 3]
# # 访问原始数据
# print(data.root)  # 输出: [1, 2, 3]
# # JSON 序列化
# print(data.model_dump_json())  # 输出: [1,2,3]

# ---------------------------------------------------------------------

# class ProductIDs(RootModel):
#     root: List[str] = Field(..., 
#                             description="产品ID列表", 
#                             min_length=1,
#                             example=["P1001", "P1002"])

# # 从API接收数据
# response_data = ["P1001", "P1002", "P1003"]
# product_ids = ProductIDs(response_data)

# # 直接用于响应
# print(product_ids.model_dump_json())  # ["P1001","P1002","P1003"]
# ---------------------------------------------------------------------
# class Coordinates(RootModel):
#     root: tuple[float, float]

# coords = Coordinates((40.7128, -74.0060))
# lat, lon = coords.root
# print(f"纬度: {lat}, 经度: {lon}")







# # ORM 模式（兼容 SQLAlchemy 等 ORM 对象）
# from pydantic import BaseModel
# from sqlalchemy import Column, Integer, String
# from sqlalchemy.orm import declarative_base

# Base = declarative_base()

# class DBUser(Base):
#     __tablename__ = "users"
#     id = Column(Integer, primary_key=True)
#     name = Column(String(50))

# # Pydantic 模型
# class User(BaseModel):
#     id: int
#     name: str

#     class Config:
#         from_attributes = True  # 启用 ORM 模式（旧版叫 `orm_mode`）

# db_user = DBUser(id=1, name="Alice")
# pydantic_user = User.model_validate(db_user)  # 直接转换 ORM 对象
# print(pydantic_user.model_dump())  # 输出: {'id': 1, 'name': 'Alice'}






# # 递归模型（自引用结构）
# from typing import Optional, List
# from pydantic import BaseModel

# class TreeNode(BaseModel):
#     value: int
#     children: Optional[List["TreeNode"]] = None  # 递归定义

# root = TreeNode(
#     value=1,
#     children=[TreeNode(value=2), TreeNode(value=3)]
# )
# print(root.model_dump_json(indent=2))





# # 字段别名与数据源映射容不同命名规范的 API 响应（如驼峰命名 vs 蛇形命名）。
# from pydantic import BaseModel, Field, AliasPath

# class User(BaseModel):
#     name: str = Field(..., alias="fullName")
#     age: int = Field(alias=("meta", "userAge"))  # 多层别名

# data = {"fullName": "Bob", "meta": {"userAge": 30}}
# user = User.model_validate(data)
# print(user.name)  # 输出: Bob






# # 自定义验证器（复杂逻辑）  业务规则校验（金额舍入、状态检查等）。
# from pydantic import BaseModel, field_validator, ValidationError

# class Payment(BaseModel):
#     amount: float
#     currency: str

#     @field_validator("currency")
#     def currency_must_be_uppercase(cls, v):
#         if v != v.upper():
#             raise ValueError("Currency must be uppercase")
#         return v

#     @field_validator("amount")
#     def round_amount(cls, v):
#         return round(v, 2)

# try:
#     Payment(amount=10.555, currency="usd")  # 触发两个错误
# except ValidationError as e:
#     print(e.errors())

# # [{'type': 'value_error', 'loc': ('currency',), 'msg': 'Value error, Currency must be uppercase', 
# # 'input': 'usd', 
# #       'ctx': 
# # {'error': ValueError('Currency must be uppercase')}, 
# # 'url': 'https://errors.pydantic.dev/2.11/v/value_error'}
# # ]    




# # 模型继承与字段覆盖  用基础模型，扩展权限系统。
# class BaseUser(BaseModel):
#     email: str
#     is_active: bool = True

# class AdminUser(BaseUser):
#     is_admin: bool = True
#     permissions: list[str] = ["read", "write"]

# admin = AdminUser(email="admin@example.com")
# print(admin.model_dump())  
# # {'email': 'admin@example.com', 'is_active': True, 'is_admin': True, 'permissions': ['read', 'write']}




# # 严格类型检查（禁用隐式转换）要求输入类型必须精确匹配（如金融系统）。
# from pydantic import BaseModel, ConfigDict, ValidationError

# class StrictModel(BaseModel):
#     model_config = ConfigDict(strict=True)  # 启用严格模式
#     id: int
#     name: str

# # 以下会报错（字符串不能隐式转整数）
# try:
#     StrictModel(id="123", name="test")
# except ValidationError as e:
#     print(e.errors()[0]["type"])  # 输出: int_parsing











# # 模型导出控制（排除/包含字段）  保护敏感数据（如密码、API密钥）。
# class SecretData(BaseModel):
#     public: str
#     secret: str  # 敏感字段

#     def model_dump(self, **kwargs):
#         kwargs.setdefault("exclude", {"secret"})  # 自动排除 secret
#         return super().model_dump(**kwargs)

# obj = SecretData(public="info", secret="password")
# print(obj.model_dump())  # 输出: {'public': 'info'} (secret 被隐藏)





# # 生成符合 OpenAPI 规范的 JSON Schema，可直接用于 FastAPI 文档。
# # JSON Schema 生成（OpenAPI 集成）
# class Product(BaseModel):
#     id: int
#     name: str = Field(..., description="产品名称")
#     price: float = Field(gt=0, description="正数价格")

# print(Product.model_json_schema())

# {'properties': {
#     'id': {'title': 'Id', 'type': 'integer'}, 
#     'name': {'description': '产品名称', 'title': 'Name', 'type': 'string'}, 
#     'price': {'description': '正数价格', 'exclusiveMinimum': 0, 'title': 'Price', 'type': 'number'}
#     }, 
#  'required': ['id', 'name', 'price'], 
#  'title': 'Product', 
#  'type': 'object'
#  }